{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "flsf21MK3KTd"
      },
      "source": [
        "# Quanvolution (Quantum convolution) for MNIST image classification with [TorchQuantum](https://github.com/mit-han-lab/torchquantum).\n",
        "<p align=\"left\">\n",
        "<img src=\"https://github.com/mit-han-lab/torchquantum/blob/master/torchquantum_logo.jpg?raw=true\" alt=\"torchquantum Logo\" width=\"250\">\n",
        "</p>\n",
        "\n",
        "Tutorial Author: Zirui Li, Hanrui Wang\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mF5Ayfdg83rT"
      },
      "source": [
        "### Outline\n",
        "1. Introduction to Quanvolutional Neural Network.\n",
        "2. Build and train a Quanvolutional Neural Network.\n",
        "  - a.  Compare Quanvolutional Neural Network with a classic model.\n",
        "  - b. Evaluate on real quantum computer.\n",
        "3. Compare multiple models with or without a trainable quanvolutional filter."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QD-1NDsh-jTm"
      },
      "source": [
        "In this tutorial, we use `tq.QuantumDevice`, `tq.GeneralEncoder`, `tq.RandomLayer`, `tq.MeasureAll`, `tq.PauliZ` class from TrochQuantum.\n",
        "\n",
        "You can learn how to build, train and evaluate a quanvolutional filter using TorchQuantum in this tutorial."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qJv0wED75YTq"
      },
      "source": [
        "## Introduction to Quanvolutional Neural Network.\n",
        "### Convolutional Neural Network\n",
        "Convolutional neural network is a classic neural network genre, mostly applied to anylize visual images. They are known for their convolutional layers that perform convolution. Typically the convolution operation is the Frobenius inner product of the convolution filter with the input image followed by an activation function. The convolution filter slides along the input image and generates a feature map. We can use the feature map for classification.\n",
        "\n",
        "<div align=\"center\">\n",
        "<img src=\"https://github.com/mit-han-lab/torchquantum/blob/master/figs/conv-full-layer.gif?raw=true\" alt=\"conv-full-layer\" width=\"300\">\n",
        "</div>\n",
        "\n",
        "### Quantum convolution\n",
        "One can extend the same idea also to the context of quantum variational circuits. Replace the classical convolution filters with variational quantum circuits and we get quanvolutional neural networks with quanvolutional filters. The quanvolutional filters perform more complex operations in a higher dimension Hilbert space than Frobenius inner product. Therefore, quanvolutional filters have more potential than traditional convolution filters.\n",
        "\n",
        "<div align=\"center\">\n",
        "<img src=\"https://github.com/mit-han-lab/torchquantum/blob/master/figs/hybridmodel.png?raw=true\" alt=\"conv-full-layer\" width=\"800\">\n",
        "</div>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Vi8LaD0p_5rm"
      },
      "source": [
        "## Build and train a Quanvolutional Neural Network."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pfwd2SNaOA4z"
      },
      "source": [
        "### Installation\n",
        "Install torchquantum and all the libs we need."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "azb47tvSiaBp",
        "outputId": "f0c4c497-aba5-479c-8979-3996db1174b6"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Collecting qiskit==0.32.1\n",
            "  Downloading qiskit-0.32.1.tar.gz (13 kB)\n",
            "Collecting qiskit-terra==0.18.3\n",
            "  Downloading qiskit_terra-0.18.3-cp37-cp37m-manylinux2010_x86_64.whl (6.1 MB)\n",
            "\u001b[K     |████████████████████████████████| 6.1 MB 4.1 MB/s \n",
            "\u001b[?25hCollecting qiskit-aer==0.9.1\n",
            "  Downloading qiskit_aer-0.9.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (17.9 MB)\n",
            "\u001b[K     |████████████████████████████████| 17.9 MB 633 kB/s \n",
            "\u001b[?25hCollecting qiskit-ibmq-provider==0.18.1\n",
            "  Downloading qiskit_ibmq_provider-0.18.1-py3-none-any.whl (237 kB)\n",
            "\u001b[K     |████████████████████████████████| 237 kB 73.3 MB/s \n",
            "\u001b[?25hCollecting qiskit-ignis==0.6.0\n",
            "  Downloading qiskit_ignis-0.6.0-py3-none-any.whl (207 kB)\n",
            "\u001b[K     |████████████████████████████████| 207 kB 65.4 MB/s \n",
            "\u001b[?25hCollecting qiskit-aqua==0.9.5\n",
            "  Downloading qiskit_aqua-0.9.5-py3-none-any.whl (2.1 MB)\n",
            "\u001b[K     |████████████████████████████████| 2.1 MB 60.5 MB/s \n",
            "\u001b[?25hRequirement already satisfied: scipy>=1.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-aer==0.9.1->qiskit==0.32.1) (1.4.1)\n",
            "Requirement already satisfied: numpy>=1.16.3 in /usr/local/lib/python3.7/dist-packages (from qiskit-aer==0.9.1->qiskit==0.32.1) (1.21.5)\n",
            "Requirement already satisfied: h5py<3.3.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit==0.32.1) (3.1.0)\n",
            "Collecting quandl\n",
            "  Downloading Quandl-3.7.0-py2.py3-none-any.whl (26 kB)\n",
            "Requirement already satisfied: scikit-learn>=0.20.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit==0.32.1) (1.0.2)\n",
            "Collecting yfinance>=0.1.62\n",
            "  Downloading yfinance-0.1.70-py2.py3-none-any.whl (26 kB)\n",
            "Requirement already satisfied: psutil>=5 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit==0.32.1) (5.4.8)\n",
            "Collecting docplex>=2.21.207\n",
            "  Downloading docplex-2.22.213.tar.gz (634 kB)\n",
            "\u001b[K     |████████████████████████████████| 634 kB 68.2 MB/s \n",
            "\u001b[?25hRequirement already satisfied: setuptools>=40.1.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit==0.32.1) (57.4.0)\n",
            "Requirement already satisfied: sympy>=1.3 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit==0.32.1) (1.7.1)\n",
            "Collecting retworkx>=0.8.0\n",
            "  Downloading retworkx-0.11.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (1.6 MB)\n",
            "\u001b[K     |████████████████████████████████| 1.6 MB 21.6 MB/s \n",
            "\u001b[?25hRequirement already satisfied: fastdtw<=0.3.4 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit==0.32.1) (0.3.4)\n",
            "Collecting dlx<=1.0.4\n",
            "  Downloading dlx-1.0.4.tar.gz (5.5 kB)\n",
            "Requirement already satisfied: pandas in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit==0.32.1) (1.3.5)\n",
            "Requirement already satisfied: urllib3>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.18.1->qiskit==0.32.1) (1.24.3)\n",
            "Requirement already satisfied: python-dateutil>=2.8.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.18.1->qiskit==0.32.1) (2.8.2)\n",
            "Collecting requests-ntlm>=1.1.0\n",
            "  Downloading requests_ntlm-1.1.0-py2.py3-none-any.whl (5.7 kB)\n",
            "Requirement already satisfied: requests>=2.19 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.18.1->qiskit==0.32.1) (2.23.0)\n",
            "Collecting websocket-client>=1.0.1\n",
            "  Downloading websocket_client-1.2.3-py3-none-any.whl (53 kB)\n",
            "\u001b[K     |████████████████████████████████| 53 kB 2.7 MB/s \n",
            "\u001b[?25hCollecting python-constraint>=1.4\n",
            "  Downloading python-constraint-1.4.0.tar.bz2 (18 kB)\n",
            "Collecting fastjsonschema>=2.10\n",
            "  Downloading fastjsonschema-2.15.3-py3-none-any.whl (22 kB)\n",
            "Collecting symengine>0.7\n",
            "  Downloading symengine-0.8.1-cp37-cp37m-manylinux2010_x86_64.whl (38.2 MB)\n",
            "\u001b[K     |████████████████████████████████| 38.2 MB 116 kB/s \n",
            "\u001b[?25hCollecting tweedledum<2.0,>=1.1\n",
            "  Downloading tweedledum-1.1.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (943 kB)\n",
            "\u001b[K     |████████████████████████████████| 943 kB 22.1 MB/s \n",
            "\u001b[?25hCollecting ply>=3.10\n",
            "  Downloading ply-3.11-py2.py3-none-any.whl (49 kB)\n",
            "\u001b[K     |████████████████████████████████| 49 kB 8.3 MB/s \n",
            "\u001b[?25hRequirement already satisfied: dill>=0.3 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.18.3->qiskit==0.32.1) (0.3.4)\n",
            "Requirement already satisfied: jsonschema>=2.6 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.18.3->qiskit==0.32.1) (4.3.3)\n",
            "Requirement already satisfied: six in /usr/local/lib/python3.7/dist-packages (from docplex>=2.21.207->qiskit-aqua==0.9.5->qiskit==0.32.1) (1.15.0)\n",
            "Requirement already satisfied: cached-property in /usr/local/lib/python3.7/dist-packages (from h5py<3.3.0->qiskit-aqua==0.9.5->qiskit==0.32.1) (1.5.2)\n",
            "Requirement already satisfied: importlib-resources>=1.4.0 in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->qiskit-terra==0.18.3->qiskit==0.32.1) (5.4.0)\n",
            "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->qiskit-terra==0.18.3->qiskit==0.32.1) (3.10.0.2)\n",
            "Requirement already satisfied: attrs>=17.4.0 in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->qiskit-terra==0.18.3->qiskit==0.32.1) (21.4.0)\n",
            "Requirement already satisfied: importlib-metadata in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->qiskit-terra==0.18.3->qiskit==0.32.1) (4.11.0)\n",
            "Requirement already satisfied: pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0 in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->qiskit-terra==0.18.3->qiskit==0.32.1) (0.18.1)\n",
            "Requirement already satisfied: zipp>=3.1.0 in /usr/local/lib/python3.7/dist-packages (from importlib-resources>=1.4.0->jsonschema>=2.6->qiskit-terra==0.18.3->qiskit==0.32.1) (3.7.0)\n",
            "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.18.1->qiskit==0.32.1) (2021.10.8)\n",
            "Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.18.1->qiskit==0.32.1) (2.10)\n",
            "Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.18.1->qiskit==0.32.1) (3.0.4)\n",
            "Collecting cryptography>=1.3\n",
            "  Downloading cryptography-36.0.1-cp36-abi3-manylinux_2_24_x86_64.whl (3.6 MB)\n",
            "\u001b[K     |████████████████████████████████| 3.6 MB 31.3 MB/s \n",
            "\u001b[?25hCollecting ntlm-auth>=1.0.2\n",
            "  Downloading ntlm_auth-1.5.0-py2.py3-none-any.whl (29 kB)\n",
            "Requirement already satisfied: cffi>=1.12 in /usr/local/lib/python3.7/dist-packages (from cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.18.1->qiskit==0.32.1) (1.15.0)\n",
            "Requirement already satisfied: pycparser in /usr/local/lib/python3.7/dist-packages (from cffi>=1.12->cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.18.1->qiskit==0.32.1) (2.21)\n",
            "Requirement already satisfied: joblib>=0.11 in /usr/local/lib/python3.7/dist-packages (from scikit-learn>=0.20.0->qiskit-aqua==0.9.5->qiskit==0.32.1) (1.1.0)\n",
            "Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.7/dist-packages (from scikit-learn>=0.20.0->qiskit-aqua==0.9.5->qiskit==0.32.1) (3.1.0)\n",
            "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.7/dist-packages (from sympy>=1.3->qiskit-aqua==0.9.5->qiskit==0.32.1) (1.2.1)\n",
            "Collecting requests>=2.19\n",
            "  Downloading requests-2.27.1-py2.py3-none-any.whl (63 kB)\n",
            "\u001b[K     |████████████████████████████████| 63 kB 814 kB/s \n",
            "\u001b[?25hRequirement already satisfied: multitasking>=0.0.7 in /usr/local/lib/python3.7/dist-packages (from yfinance>=0.1.62->qiskit-aqua==0.9.5->qiskit==0.32.1) (0.0.10)\n",
            "Collecting lxml>=4.5.1\n",
            "  Downloading lxml-4.7.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl (6.4 MB)\n",
            "\u001b[K     |████████████████████████████████| 6.4 MB 30.3 MB/s \n",
            "\u001b[?25hRequirement already satisfied: pytz>=2017.3 in /usr/local/lib/python3.7/dist-packages (from pandas->qiskit-aqua==0.9.5->qiskit==0.32.1) (2018.9)\n",
            "Requirement already satisfied: charset-normalizer~=2.0.0 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.18.1->qiskit==0.32.1) (2.0.11)\n",
            "Collecting inflection>=0.3.1\n",
            "  Downloading inflection-0.5.1-py2.py3-none-any.whl (9.5 kB)\n",
            "Requirement already satisfied: more-itertools in /usr/local/lib/python3.7/dist-packages (from quandl->qiskit-aqua==0.9.5->qiskit==0.32.1) (8.12.0)\n",
            "Building wheels for collected packages: qiskit, dlx, docplex, python-constraint\n",
            "  Building wheel for qiskit (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
            "  Created wheel for qiskit: filename=qiskit-0.32.1-py3-none-any.whl size=11777 sha256=911365fec91e5c648d2569b156af429c0aff7c3d95d453a7d24e6bf8d7d1a315\n",
            "  Stored in directory: /root/.cache/pip/wheels/0f/62/0a/c53eda1ead41c137c47c9730bc2771a8367b1ce00fb64e8cc6\n",
            "  Building wheel for dlx (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
            "  Created wheel for dlx: filename=dlx-1.0.4-py3-none-any.whl size=5718 sha256=cb913d8c2b19d87e8784f4220a02752c4858e3ebe531b0e80ab22c5625c1bd0b\n",
            "  Stored in directory: /root/.cache/pip/wheels/78/55/c8/dc61e772445a566b7608a476d151e9dcaf4e092b01b0c4bc3c\n",
            "  Building wheel for docplex (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
            "  Created wheel for docplex: filename=docplex-2.22.213-py3-none-any.whl size=696882 sha256=192bab0a2587503608ce12a090c9f129f2a6b0e88f3a41e568c07ca585b4e3ff\n",
            "  Stored in directory: /root/.cache/pip/wheels/90/69/6b/1375c68a5b7ff94c40263b151c86f58bd72200bf0c465b5ba3\n",
            "  Building wheel for python-constraint (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
            "  Created wheel for python-constraint: filename=python_constraint-1.4.0-py2.py3-none-any.whl size=24081 sha256=77684dcb7c666715267053a0114cf933c5c52cb7af9a30645de961f9af12c323\n",
            "  Stored in directory: /root/.cache/pip/wheels/07/27/db/1222c80eb1e431f3d2199c12569cb1cac60f562a451fe30479\n",
            "Successfully built qiskit dlx docplex python-constraint\n",
            "Installing collected packages: tweedledum, symengine, retworkx, python-constraint, ply, fastjsonschema, requests, qiskit-terra, ntlm-auth, lxml, inflection, cryptography, yfinance, websocket-client, requests-ntlm, quandl, qiskit-ignis, docplex, dlx, qiskit-ibmq-provider, qiskit-aqua, qiskit-aer, qiskit\n",
            "  Attempting uninstall: requests\n",
            "    Found existing installation: requests 2.23.0\n",
            "    Uninstalling requests-2.23.0:\n",
            "      Successfully uninstalled requests-2.23.0\n",
            "  Attempting uninstall: lxml\n",
            "    Found existing installation: lxml 4.2.6\n",
            "    Uninstalling lxml-4.2.6:\n",
            "      Successfully uninstalled lxml-4.2.6\n",
            "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n",
            "google-colab 1.0.0 requires requests~=2.23.0, but you have requests 2.27.1 which is incompatible.\n",
            "datascience 0.10.6 requires folium==0.2.1, but you have folium 0.8.3 which is incompatible.\u001b[0m\n",
            "Successfully installed cryptography-36.0.1 dlx-1.0.4 docplex-2.22.213 fastjsonschema-2.15.3 inflection-0.5.1 lxml-4.7.1 ntlm-auth-1.5.0 ply-3.11 python-constraint-1.4.0 qiskit-0.32.1 qiskit-aer-0.9.1 qiskit-aqua-0.9.5 qiskit-ibmq-provider-0.18.1 qiskit-ignis-0.6.0 qiskit-terra-0.18.3 quandl-3.7.0 requests-2.27.1 requests-ntlm-1.1.0 retworkx-0.11.0 symengine-0.8.1 tweedledum-1.1.1 websocket-client-1.2.3 yfinance-0.1.70\n"
          ]
        }
      ],
      "source": [
        "!pip install qiskit==0.32.1"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "F2-0UpluOIQl"
      },
      "source": [
        "Download and cd to the repo."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "6sNqLl9tjjAf",
        "outputId": "0521caf5-e275-4379-87f4-fdf3cce8cb5e"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Cloning into 'torchquantum'...\n",
            "remote: Enumerating objects: 10737, done.\u001b[K\n",
            "remote: Counting objects: 100% (7529/7529), done.\u001b[K\n",
            "remote: Compressing objects: 100% (3777/3777), done.\u001b[K\n",
            "remote: Total 10737 (delta 3765), reused 7076 (delta 3348), pack-reused 3208\u001b[K\n",
            "Receiving objects: 100% (10737/10737), 3.19 MiB | 12.92 MiB/s, done.\n",
            "Resolving deltas: 100% (5732/5732), done.\n",
            "Checking out files: 100% (50055/50055), done.\n"
          ]
        }
      ],
      "source": [
        "!git clone https://github.com/mit-han-lab/torchquantum.git"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "0c2MCqFXjxkD",
        "outputId": "bde0ae24-ccf7-4d0f-d9fd-c45373d300ed"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "/content/torchquantum\n"
          ]
        }
      ],
      "source": [
        "%cd torchquantum"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PO1xLbaOOxWk"
      },
      "source": [
        "Install torch-quantum."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "3c6nfq3KkVXG",
        "outputId": "66d0d71e-9755-4db4-ccab-605afeeca03c"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Obtaining file:///content/torchquantum\n",
            "Requirement already satisfied: numpy>=1.19.2 in /usr/local/lib/python3.7/dist-packages (from torchquantum==0.1.0) (1.21.5)\n",
            "Requirement already satisfied: torchvision>=0.9.0.dev20210130 in /usr/local/lib/python3.7/dist-packages (from torchquantum==0.1.0) (0.11.1+cu111)\n",
            "Requirement already satisfied: tqdm>=4.56.0 in /usr/local/lib/python3.7/dist-packages (from torchquantum==0.1.0) (4.62.3)\n",
            "Requirement already satisfied: setuptools>=52.0.0 in /usr/local/lib/python3.7/dist-packages (from torchquantum==0.1.0) (57.4.0)\n",
            "Requirement already satisfied: torch>=1.8.0 in /usr/local/lib/python3.7/dist-packages (from torchquantum==0.1.0) (1.10.0+cu111)\n",
            "Collecting torchpack>=0.3.0\n",
            "  Downloading torchpack-0.3.1-py3-none-any.whl (34 kB)\n",
            "Requirement already satisfied: qiskit>=0.32.0 in /usr/local/lib/python3.7/dist-packages (from torchquantum==0.1.0) (0.32.1)\n",
            "Collecting matplotlib>=3.3.2\n",
            "  Downloading matplotlib-3.5.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl (11.2 MB)\n",
            "\u001b[K     |████████████████████████████████| 11.2 MB 6.5 MB/s \n",
            "\u001b[?25hCollecting pathos>=0.2.7\n",
            "  Downloading pathos-0.2.8-py2.py3-none-any.whl (81 kB)\n",
            "\u001b[K     |████████████████████████████████| 81 kB 12.1 MB/s \n",
            "\u001b[?25hRequirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=3.3.2->torchquantum==0.1.0) (2.8.2)\n",
            "Requirement already satisfied: pyparsing>=2.2.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=3.3.2->torchquantum==0.1.0) (3.0.7)\n",
            "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=3.3.2->torchquantum==0.1.0) (0.11.0)\n",
            "Collecting fonttools>=4.22.0\n",
            "  Downloading fonttools-4.29.1-py3-none-any.whl (895 kB)\n",
            "\u001b[K     |████████████████████████████████| 895 kB 55.2 MB/s \n",
            "\u001b[?25hRequirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=3.3.2->torchquantum==0.1.0) (7.1.2)\n",
            "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=3.3.2->torchquantum==0.1.0) (1.3.2)\n",
            "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.7/dist-packages (from matplotlib>=3.3.2->torchquantum==0.1.0) (21.3)\n",
            "Collecting ppft>=1.6.6.4\n",
            "  Downloading ppft-1.6.6.4-py3-none-any.whl (65 kB)\n",
            "\u001b[K     |████████████████████████████████| 65 kB 4.1 MB/s \n",
            "\u001b[?25hCollecting pox>=0.3.0\n",
            "  Downloading pox-0.3.0-py2.py3-none-any.whl (30 kB)\n",
            "Requirement already satisfied: multiprocess>=0.70.12 in /usr/local/lib/python3.7/dist-packages (from pathos>=0.2.7->torchquantum==0.1.0) (0.70.12.2)\n",
            "Requirement already satisfied: dill>=0.3.4 in /usr/local/lib/python3.7/dist-packages (from pathos>=0.2.7->torchquantum==0.1.0) (0.3.4)\n",
            "Requirement already satisfied: six>=1.7.3 in /usr/local/lib/python3.7/dist-packages (from ppft>=1.6.6.4->pathos>=0.2.7->torchquantum==0.1.0) (1.15.0)\n",
            "Requirement already satisfied: qiskit-ibmq-provider==0.18.1 in /usr/local/lib/python3.7/dist-packages (from qiskit>=0.32.0->torchquantum==0.1.0) (0.18.1)\n",
            "Requirement already satisfied: qiskit-aqua==0.9.5 in /usr/local/lib/python3.7/dist-packages (from qiskit>=0.32.0->torchquantum==0.1.0) (0.9.5)\n",
            "Requirement already satisfied: qiskit-aer==0.9.1 in /usr/local/lib/python3.7/dist-packages (from qiskit>=0.32.0->torchquantum==0.1.0) (0.9.1)\n",
            "Requirement already satisfied: qiskit-ignis==0.6.0 in /usr/local/lib/python3.7/dist-packages (from qiskit>=0.32.0->torchquantum==0.1.0) (0.6.0)\n",
            "Requirement already satisfied: qiskit-terra==0.18.3 in /usr/local/lib/python3.7/dist-packages (from qiskit>=0.32.0->torchquantum==0.1.0) (0.18.3)\n",
            "Requirement already satisfied: scipy>=1.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-aer==0.9.1->qiskit>=0.32.0->torchquantum==0.1.0) (1.4.1)\n",
            "Requirement already satisfied: quandl in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (3.7.0)\n",
            "Requirement already satisfied: scikit-learn>=0.20.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (1.0.2)\n",
            "Requirement already satisfied: pandas in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (1.3.5)\n",
            "Requirement already satisfied: h5py<3.3.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (3.1.0)\n",
            "Requirement already satisfied: fastdtw<=0.3.4 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (0.3.4)\n",
            "Requirement already satisfied: dlx<=1.0.4 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (1.0.4)\n",
            "Requirement already satisfied: retworkx>=0.8.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (0.11.0)\n",
            "Requirement already satisfied: sympy>=1.3 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (1.7.1)\n",
            "Requirement already satisfied: docplex>=2.21.207 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (2.22.213)\n",
            "Requirement already satisfied: yfinance>=0.1.62 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (0.1.70)\n",
            "Requirement already satisfied: psutil>=5 in /usr/local/lib/python3.7/dist-packages (from qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (5.4.8)\n",
            "Requirement already satisfied: urllib3>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.18.1->qiskit>=0.32.0->torchquantum==0.1.0) (1.24.3)\n",
            "Requirement already satisfied: requests-ntlm>=1.1.0 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.18.1->qiskit>=0.32.0->torchquantum==0.1.0) (1.1.0)\n",
            "Requirement already satisfied: websocket-client>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.18.1->qiskit>=0.32.0->torchquantum==0.1.0) (1.2.3)\n",
            "Requirement already satisfied: requests>=2.19 in /usr/local/lib/python3.7/dist-packages (from qiskit-ibmq-provider==0.18.1->qiskit>=0.32.0->torchquantum==0.1.0) (2.27.1)\n",
            "Requirement already satisfied: symengine>0.7 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.18.3->qiskit>=0.32.0->torchquantum==0.1.0) (0.8.1)\n",
            "Requirement already satisfied: fastjsonschema>=2.10 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.18.3->qiskit>=0.32.0->torchquantum==0.1.0) (2.15.3)\n",
            "Requirement already satisfied: ply>=3.10 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.18.3->qiskit>=0.32.0->torchquantum==0.1.0) (3.11)\n",
            "Requirement already satisfied: python-constraint>=1.4 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.18.3->qiskit>=0.32.0->torchquantum==0.1.0) (1.4.0)\n",
            "Requirement already satisfied: jsonschema>=2.6 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.18.3->qiskit>=0.32.0->torchquantum==0.1.0) (4.3.3)\n",
            "Requirement already satisfied: tweedledum<2.0,>=1.1 in /usr/local/lib/python3.7/dist-packages (from qiskit-terra==0.18.3->qiskit>=0.32.0->torchquantum==0.1.0) (1.1.1)\n",
            "Requirement already satisfied: cached-property in /usr/local/lib/python3.7/dist-packages (from h5py<3.3.0->qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (1.5.2)\n",
            "Requirement already satisfied: attrs>=17.4.0 in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->qiskit-terra==0.18.3->qiskit>=0.32.0->torchquantum==0.1.0) (21.4.0)\n",
            "Requirement already satisfied: importlib-metadata in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->qiskit-terra==0.18.3->qiskit>=0.32.0->torchquantum==0.1.0) (4.11.0)\n",
            "Requirement already satisfied: importlib-resources>=1.4.0 in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->qiskit-terra==0.18.3->qiskit>=0.32.0->torchquantum==0.1.0) (5.4.0)\n",
            "Requirement already satisfied: pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0 in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->qiskit-terra==0.18.3->qiskit>=0.32.0->torchquantum==0.1.0) (0.18.1)\n",
            "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from jsonschema>=2.6->qiskit-terra==0.18.3->qiskit>=0.32.0->torchquantum==0.1.0) (3.10.0.2)\n",
            "Requirement already satisfied: zipp>=3.1.0 in /usr/local/lib/python3.7/dist-packages (from importlib-resources>=1.4.0->jsonschema>=2.6->qiskit-terra==0.18.3->qiskit>=0.32.0->torchquantum==0.1.0) (3.7.0)\n",
            "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.18.1->qiskit>=0.32.0->torchquantum==0.1.0) (2.10)\n",
            "Requirement already satisfied: charset-normalizer~=2.0.0 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.18.1->qiskit>=0.32.0->torchquantum==0.1.0) (2.0.11)\n",
            "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.18.1->qiskit>=0.32.0->torchquantum==0.1.0) (2021.10.8)\n",
            "Requirement already satisfied: cryptography>=1.3 in /usr/local/lib/python3.7/dist-packages (from requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.18.1->qiskit>=0.32.0->torchquantum==0.1.0) (36.0.1)\n",
            "Requirement already satisfied: ntlm-auth>=1.0.2 in /usr/local/lib/python3.7/dist-packages (from requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.18.1->qiskit>=0.32.0->torchquantum==0.1.0) (1.5.0)\n",
            "Requirement already satisfied: cffi>=1.12 in /usr/local/lib/python3.7/dist-packages (from cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.18.1->qiskit>=0.32.0->torchquantum==0.1.0) (1.15.0)\n",
            "Requirement already satisfied: pycparser in /usr/local/lib/python3.7/dist-packages (from cffi>=1.12->cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.18.1->qiskit>=0.32.0->torchquantum==0.1.0) (2.21)\n",
            "Requirement already satisfied: joblib>=0.11 in /usr/local/lib/python3.7/dist-packages (from scikit-learn>=0.20.0->qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (1.1.0)\n",
            "Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.7/dist-packages (from scikit-learn>=0.20.0->qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (3.1.0)\n",
            "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.7/dist-packages (from sympy>=1.3->qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (1.2.1)\n",
            "Requirement already satisfied: tensorboard in /usr/local/lib/python3.7/dist-packages (from torchpack>=0.3.0->torchquantum==0.1.0) (2.8.0)\n",
            "Collecting toml\n",
            "  Downloading toml-0.10.2-py2.py3-none-any.whl (16 kB)\n",
            "Collecting tensorpack\n",
            "  Downloading tensorpack-0.11-py2.py3-none-any.whl (296 kB)\n",
            "\u001b[K     |████████████████████████████████| 296 kB 57.1 MB/s \n",
            "\u001b[?25hCollecting multimethod\n",
            "  Downloading multimethod-1.7-py3-none-any.whl (9.5 kB)\n",
            "Collecting loguru\n",
            "  Downloading loguru-0.6.0-py3-none-any.whl (58 kB)\n",
            "\u001b[K     |████████████████████████████████| 58 kB 2.6 MB/s \n",
            "\u001b[?25hRequirement already satisfied: pyyaml in /usr/local/lib/python3.7/dist-packages (from torchpack>=0.3.0->torchquantum==0.1.0) (3.13)\n",
            "Requirement already satisfied: multitasking>=0.0.7 in /usr/local/lib/python3.7/dist-packages (from yfinance>=0.1.62->qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (0.0.10)\n",
            "Requirement already satisfied: lxml>=4.5.1 in /usr/local/lib/python3.7/dist-packages (from yfinance>=0.1.62->qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (4.7.1)\n",
            "Requirement already satisfied: pytz>=2017.3 in /usr/local/lib/python3.7/dist-packages (from pandas->qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (2018.9)\n",
            "Requirement already satisfied: more-itertools in /usr/local/lib/python3.7/dist-packages (from quandl->qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (8.12.0)\n",
            "Requirement already satisfied: inflection>=0.3.1 in /usr/local/lib/python3.7/dist-packages (from quandl->qiskit-aqua==0.9.5->qiskit>=0.32.0->torchquantum==0.1.0) (0.5.1)\n",
            "Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.7/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (3.3.6)\n",
            "Requirement already satisfied: tensorboard-plugin-wit>=1.6.0 in /usr/local/lib/python3.7/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (1.8.1)\n",
            "Requirement already satisfied: absl-py>=0.4 in /usr/local/lib/python3.7/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (1.0.0)\n",
            "Requirement already satisfied: grpcio>=1.24.3 in /usr/local/lib/python3.7/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (1.43.0)\n",
            "Requirement already satisfied: wheel>=0.26 in /usr/local/lib/python3.7/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (0.37.1)\n",
            "Requirement already satisfied: google-auth-oauthlib<0.5,>=0.4.1 in /usr/local/lib/python3.7/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (0.4.6)\n",
            "Requirement already satisfied: google-auth<3,>=1.6.3 in /usr/local/lib/python3.7/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (1.35.0)\n",
            "Requirement already satisfied: tensorboard-data-server<0.7.0,>=0.6.0 in /usr/local/lib/python3.7/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (0.6.1)\n",
            "Requirement already satisfied: werkzeug>=0.11.15 in /usr/local/lib/python3.7/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (1.0.1)\n",
            "Requirement already satisfied: protobuf>=3.6.0 in /usr/local/lib/python3.7/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (3.17.3)\n",
            "Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.7/dist-packages (from google-auth<3,>=1.6.3->tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (0.2.8)\n",
            "Requirement already satisfied: cachetools<5.0,>=2.0.0 in /usr/local/lib/python3.7/dist-packages (from google-auth<3,>=1.6.3->tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (4.2.4)\n",
            "Requirement already satisfied: rsa<5,>=3.1.4 in /usr/local/lib/python3.7/dist-packages (from google-auth<3,>=1.6.3->tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (4.8)\n",
            "Requirement already satisfied: requests-oauthlib>=0.7.0 in /usr/local/lib/python3.7/dist-packages (from google-auth-oauthlib<0.5,>=0.4.1->tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (1.3.1)\n",
            "Requirement already satisfied: pyasn1<0.5.0,>=0.4.6 in /usr/local/lib/python3.7/dist-packages (from pyasn1-modules>=0.2.1->google-auth<3,>=1.6.3->tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (0.4.8)\n",
            "Requirement already satisfied: oauthlib>=3.0.0 in /usr/local/lib/python3.7/dist-packages (from requests-oauthlib>=0.7.0->google-auth-oauthlib<0.5,>=0.4.1->tensorboard->torchpack>=0.3.0->torchquantum==0.1.0) (3.2.0)\n",
            "Requirement already satisfied: msgpack>=0.5.2 in /usr/local/lib/python3.7/dist-packages (from tensorpack->torchpack>=0.3.0->torchquantum==0.1.0) (1.0.3)\n",
            "Requirement already satisfied: pyzmq>=16 in /usr/local/lib/python3.7/dist-packages (from tensorpack->torchpack>=0.3.0->torchquantum==0.1.0) (22.3.0)\n",
            "Collecting msgpack-numpy>=0.4.4.2\n",
            "  Downloading msgpack_numpy-0.4.7.1-py2.py3-none-any.whl (6.7 kB)\n",
            "Requirement already satisfied: tabulate>=0.7.7 in /usr/local/lib/python3.7/dist-packages (from tensorpack->torchpack>=0.3.0->torchquantum==0.1.0) (0.8.9)\n",
            "Requirement already satisfied: termcolor>=1.1 in /usr/local/lib/python3.7/dist-packages (from tensorpack->torchpack>=0.3.0->torchquantum==0.1.0) (1.1.0)\n",
            "Installing collected packages: msgpack-numpy, toml, tensorpack, ppft, pox, multimethod, loguru, fonttools, torchpack, pathos, matplotlib, torchquantum\n",
            "  Attempting uninstall: matplotlib\n",
            "    Found existing installation: matplotlib 3.2.2\n",
            "    Uninstalling matplotlib-3.2.2:\n",
            "      Successfully uninstalled matplotlib-3.2.2\n",
            "  Running setup.py develop for torchquantum\n",
            "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n",
            "albumentations 0.1.12 requires imgaug<0.2.7,>=0.2.5, but you have imgaug 0.2.9 which is incompatible.\u001b[0m\n",
            "Successfully installed fonttools-4.29.1 loguru-0.6.0 matplotlib-3.5.1 msgpack-numpy-0.4.7.1 multimethod-1.7 pathos-0.2.8 pox-0.3.0 ppft-1.6.6.4 tensorpack-0.11 toml-0.10.2 torchpack-0.3.1 torchquantum-0.1.0\n"
          ]
        },
        {
          "data": {
            "application/vnd.colab-display-data+json": {
              "pip_warning": {
                "packages": [
                  "matplotlib",
                  "mpl_toolkits"
                ]
              }
            }
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "!pip install --editable ."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "18tqleq4O3cX"
      },
      "source": [
        "Change PYTHONPATH and install other packages."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "d7ZPp7FikrZz",
        "outputId": "514f9e33-cc82-4ca8-daad-63c7971bd78d"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "env: PYTHONPATH=.\n"
          ]
        }
      ],
      "source": [
        "%env PYTHONPATH=."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rhsBhV23PD4g"
      },
      "source": [
        "Run the following code to store a qiskit token. You can replace it with your own token from your IBMQ account if you like.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Iw9rQ6dcnrhe"
      },
      "outputs": [],
      "source": [
        "from qiskit import IBMQ\n",
        "# IBMQ.save_account('', overwrite=True)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Nvn9EkRH5fTs",
        "outputId": "9dc223b4-acbf-4fcc-9dc9-dd772d71eecc"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Collecting matplotlib==3.1.3\n",
            "  Downloading matplotlib-3.1.3-cp37-cp37m-manylinux1_x86_64.whl (13.1 MB)\n",
            "\u001b[K     |████████████████████████████████| 13.1 MB 4.3 MB/s \n",
            "\u001b[?25hRequirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib==3.1.3) (3.0.7)\n",
            "Requirement already satisfied: numpy>=1.11 in /usr/local/lib/python3.7/dist-packages (from matplotlib==3.1.3) (1.21.5)\n",
            "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib==3.1.3) (0.11.0)\n",
            "Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib==3.1.3) (2.8.2)\n",
            "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib==3.1.3) (1.3.2)\n",
            "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/dist-packages (from python-dateutil>=2.1->matplotlib==3.1.3) (1.15.0)\n",
            "Installing collected packages: matplotlib\n",
            "  Attempting uninstall: matplotlib\n",
            "    Found existing installation: matplotlib 3.5.1\n",
            "    Uninstalling matplotlib-3.5.1:\n",
            "      Successfully uninstalled matplotlib-3.5.1\n",
            "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n",
            "torchquantum 0.1.0 requires matplotlib>=3.3.2, but you have matplotlib 3.1.3 which is incompatible.\n",
            "albumentations 0.1.12 requires imgaug<0.2.7,>=0.2.5, but you have imgaug 0.2.9 which is incompatible.\u001b[0m\n",
            "Successfully installed matplotlib-3.1.3\n"
          ]
        },
        {
          "data": {
            "application/vnd.colab-display-data+json": {
              "pip_warning": {
                "packages": [
                  "matplotlib",
                  "mpl_toolkits"
                ]
              }
            }
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "!pip install matplotlib==3.1.3"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-42mdL8CG5Vi"
      },
      "source": [
        "### Step\n",
        "Our code requires torchquantum lib, mnist dataset, pytorch and numpy. We need torch and the logsoftmax function from `torch.nn.functional`, optimizers(`optim`), `torchquantum` module, MNIST dataset(`MNIST`), cosine annealing learning rate(`CosineAnnealingLR`).\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "N5acspJ8G1n3"
      },
      "outputs": [],
      "source": [
        "import torch\n",
        "import torch.nn.functional as F\n",
        "import torch.optim as optim\n",
        "import numpy as np\n",
        "\n",
        "import torchquantum as tq\n",
        "import random\n",
        "\n",
        "from torchquantum.datasets import MNIST\n",
        "from torch.optim.lr_scheduler import CosineAnnealingLR"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QiOV-xIGKXVK"
      },
      "source": [
        "### Build a quanvolutional filter\n",
        "Our quanvolution model is a hybrid model. It consists of two parts, the quanvolutional filter part and the classical layer part. To build the model, firstly we define our quanvolutional filter.\n",
        "\n",
        "Our quanvolutional filter’s structure is the same as the figure described above. It has four qubits. The `tq.QuantumDevice` module stores the state vector. Usually a Quantum Neural Network module consists of three parts: encoder, ansatz and measurement. We can create an encoder by passing a list of gates to `tq.GeneralEncoder`. Each entry in the list contains `input_idx`, `func`, and `wires`. Here, each qubit has a rotation-Y gate. 4 RY gates in total. They can encode the 2x2 input data to the quantum state. Then we decide our ansatz to be a random layer. We call `tq.RandomLayer` to create an ansatz composed by 8 basic gates with no more than 8 trainable parameters. And finally we perform Pauli-Z measurements on each qubit by creating a `tq.MeasureAll` module and passing `tq.PauliZ` to it. The measure function will return four expectation values from four qubits. The four results go to four channels.\n",
        "\n",
        "Next look at how quanvolutional filter works. We get the batch size. Our image is 28x28. So we reshape our input data to `(bsz, 28, 28)`.\n",
        "\n",
        "We initialize the `data_list`. The list stores the outputs in each stride.\n",
        "\n",
        "The double loop is to iterate all the possible positions that the quanvolutional filter window may stride in. Here the stride is 2.\n",
        "\n",
        "Then we catenate the data in the 2x2 window. Here we catenate four lists to one big list, so we need to reshape the list to `(4, bsz)` and transpose it to `(bsz, 4)`.\n",
        "\n",
        "Next if you want to use qiskit’s remote noise model or real quantum machine, you can set `use_qiskit=True` and pass these 5 parameters: `q_device`, `encoder`, `q_layer`, `measure`, and `data`. The `qiskit_processor` will receive these parameters, put the data in the encoder, run the while circuits and return the measurement result. Remember only when the model is doing an inference can you use qiskit remote.\n",
        "\n",
        "If you are training or not using qiskit remote, you can run the three parts one by one on google colab’s GPU.\n",
        "\n",
        "After each stride, we append the measurement result to `data_list`.\n",
        "\n",
        "Finally, we catenate the `data_list` along dimension 1 and return the result.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "iBnWI5yqKfMB"
      },
      "outputs": [],
      "source": [
        "class QuanvolutionFilter(tq.QuantumModule):\n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.n_wires = 4\n",
        "        self.q_device = tq.QuantumDevice(n_wires=self.n_wires)\n",
        "        self.encoder = tq.GeneralEncoder(\n",
        "        [   {'input_idx': [0], 'func': 'ry', 'wires': [0]},\n",
        "            {'input_idx': [1], 'func': 'ry', 'wires': [1]},\n",
        "            {'input_idx': [2], 'func': 'ry', 'wires': [2]},\n",
        "            {'input_idx': [3], 'func': 'ry', 'wires': [3]},])\n",
        "\n",
        "        self.q_layer = tq.RandomLayer(n_ops=8, wires=list(range(self.n_wires)))\n",
        "        self.measure = tq.MeasureAll(tq.PauliZ)\n",
        "\n",
        "    def forward(self, x, use_qiskit=False):\n",
        "        bsz = x.shape[0]\n",
        "        size = 28\n",
        "        x = x.view(bsz, size, size)\n",
        "\n",
        "        data_list = []\n",
        "\n",
        "        for c in range(0, size, 2):\n",
        "            for r in range(0, size, 2):\n",
        "                data = torch.transpose(torch.cat((x[:, c, r], x[:, c, r+1], x[:, c+1, r], x[:, c+1, r+1])).view(4, bsz), 0, 1)\n",
        "                if use_qiskit:\n",
        "                    data = self.qiskit_processor.process_parameterized(\n",
        "                        self.q_device, self.encoder, self.q_layer, self.measure, data)\n",
        "                else:\n",
        "                    self.encoder(self.q_device, data)\n",
        "                    self.q_layer(self.q_device)\n",
        "                    data = self.measure(self.q_device)\n",
        "\n",
        "                data_list.append(data.view(bsz, 4))\n",
        "        \n",
        "        result = torch.cat(data_list, dim=1).float()\n",
        "        \n",
        "        return result\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "KpVfJUezK7ny"
      },
      "source": [
        "### Build the whole hybrid model.\n",
        "\n",
        "Then we look at the whole model. The whole model consists of a `QuanvolutionFilter` and full connect layer(`torch.nn.Linear`). The size of input is 4\\*14\\*14 because a 28x28 image after quanvolutional filter turns into a 4 channel 14x14 feature. As the task is MNIST 10 digits classification, the size of output is 10. At last the model perform `F.logsoftmax` to the result for classification.\n",
        "\n",
        "<div align=\"center\">\n",
        "<img src=\"https://github.com/mit-han-lab/torchquantum/blob/master/figs/hybridmodel.png?raw=true\" alt=\"conv-full-layer\" width=\"800\">\n",
        "</div>\n",
        "\n",
        "Here, we also has a model without quanvolutional filters used for comparison. Its full connect layer’s input size is simple 28x28.\n",
        "\n",
        "<div align=\"center\">\n",
        "<img src=\"https://github.com/mit-han-lab/torchquantum/blob/master/figs/classicalmodel.png?raw=true\" alt=\"conv-full-layer\" width=\"400\">\n",
        "</div>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "UbhzYiGcK9xk"
      },
      "outputs": [],
      "source": [
        "class HybridModel(torch.nn.Module):\n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.qf = QuanvolutionFilter()\n",
        "        self.linear = torch.nn.Linear(4*14*14, 10)\n",
        "    \n",
        "    def forward(self, x, use_qiskit=False):\n",
        "        with torch.no_grad():\n",
        "          x = self.qf(x, use_qiskit)\n",
        "        x = self.linear(x)\n",
        "        return F.log_softmax(x, -1)\n",
        "\n",
        "class HybridModel_without_qf(torch.nn.Module):\n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.linear = torch.nn.Linear(28*28, 10)\n",
        "    \n",
        "    def forward(self, x, use_qiskit=False):\n",
        "        x = x.view(-1, 28*28)\n",
        "        x = self.linear(x)\n",
        "        return F.log_softmax(x, -1)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AXwEp5SILF_Z"
      },
      "source": [
        "### Load the dataset MNIST\n",
        "We use MNIST classification dataset(10 digits and 1000 training samples).\n",
        "\n",
        "The `root` is the folder that stores the dataset. If there’s no MNIST dataset in root, it will automatically download MNIST.\n",
        "Next, we set the `train_valid_split_ratio`, `n_test_samples`, and `n_train_samples`.\n",
        "\n",
        "The dataset now contains three splits, 'train', 'valid' and 'test'. For each split, we create a dataloader with a random sampler, `batch_size` is 10, `num_workers` is 8 and `pin_memory` is true."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 512,
          "referenced_widgets": [
            "ddcca6cc591f45a887f80bcc5d27ce13",
            "c8c570bdf96340c1bbf4e612f3d0c3c4",
            "30b8e4960e564891ad81ac242c228b25",
            "c46454929cae4e89976f42d9bc391a94",
            "ace3e747ccfd4f9f9faf46ce34936ce1",
            "d274e40c0adb4d3e80e8d1cf5ad475ee",
            "a8e8fb1c355445698cbc828dddffb9e5",
            "d312e5166b28438da2b9e91de91f0e09",
            "dc961678433f488babca027e197d2aa1",
            "5335eb0e67f84c85b9efacc7793d24fd",
            "34e1a2b9f934411090026a0ee98a3b5b",
            "23dbd6346f684afebcc4ea0d3e72a67e",
            "e85d5726a566462e962baa75f32074d6",
            "3b090dcf208c4822892a0afc2ba2e6a9",
            "d0a2f52a311541a686f592a985e1aac0",
            "41e329d1bd764c7cad4d2e834df50cd9",
            "5de520efee524ca28ed5b1b42861bef7",
            "b6d2f65a2e644523b7ecc6e3e9e17de3",
            "4abe9a5443514e00a536c839a9a5e04d",
            "b2ca643df597463dad1d5efe8abf64c4",
            "c168c7416db742f5bc74d45fe4a9bf05",
            "26d0390ad17048799741582271721a3e",
            "f314f3212d8f49468ccce3ad1cb8af6e",
            "694229176eb84488811763e57ccdbd9f",
            "32bd67ddf3a44b879cb123aa797627c0",
            "237d834d5fd74efa947683722d3e0e37",
            "29be09a9c5344928a9d2dda75ed8680c",
            "7584295a605c4a99a4dccce31be4cb2d",
            "e81b4f6589d649758fd2cd18da8ab35f",
            "f86c7ffecc394345a4eeb587cfd404d1",
            "c893fabe4af6410d837a0bd191df61d9",
            "f69883e80817409c9a10a2ec6d6ef68c",
            "45f166ea914e49c5bcf2ec39a649e351",
            "ae65786c8b1e4e789ecb72bcd6b9b211",
            "cfc67a5bebd247838d29b9babacbc103",
            "5953a85cd7334c828cf5005b2807fa41",
            "952170c8ff4d4fa9b7141d372b35cdd1",
            "7cbce63b72c843e9ad824dce59a7e2fb",
            "18acae4757154a10a7e2b9ebe4fbd53b",
            "364f865b5e334ac6add27ef1a32b8173",
            "e2b60171e7ca45bea357831419d2f9c6",
            "3f37e8639ddd4a6eac44420ce3275cd7",
            "1c75908cdb0d4909a266ef3f0184c13d",
            "393cc69622f3428fba3e10886e5ab65d"
          ]
        },
        "id": "taGjJMVcLN2L",
        "outputId": "3b8c1fcd-ade1-4530-d104-36b76b1341f7"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz\n",
            "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz to ./mnist_data/MNIST/raw/train-images-idx3-ubyte.gz\n"
          ]
        },
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "ddcca6cc591f45a887f80bcc5d27ce13",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "  0%|          | 0/9912422 [00:00<?, ?it/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Extracting ./mnist_data/MNIST/raw/train-images-idx3-ubyte.gz to ./mnist_data/MNIST/raw\n",
            "\n",
            "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz\n",
            "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz to ./mnist_data/MNIST/raw/train-labels-idx1-ubyte.gz\n"
          ]
        },
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "23dbd6346f684afebcc4ea0d3e72a67e",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "  0%|          | 0/28881 [00:00<?, ?it/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Extracting ./mnist_data/MNIST/raw/train-labels-idx1-ubyte.gz to ./mnist_data/MNIST/raw\n",
            "\n",
            "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz\n",
            "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz to ./mnist_data/MNIST/raw/t10k-images-idx3-ubyte.gz\n"
          ]
        },
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "f314f3212d8f49468ccce3ad1cb8af6e",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "  0%|          | 0/1648877 [00:00<?, ?it/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Extracting ./mnist_data/MNIST/raw/t10k-images-idx3-ubyte.gz to ./mnist_data/MNIST/raw\n",
            "\n",
            "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz\n",
            "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz to ./mnist_data/MNIST/raw/t10k-labels-idx1-ubyte.gz\n"
          ]
        },
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "ae65786c8b1e4e789ecb72bcd6b9b211",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "  0%|          | 0/4542 [00:00<?, ?it/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "[2022-02-16 04:00:40.771] Only use the front 500 images as TRAIN set.\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Extracting ./mnist_data/MNIST/raw/t10k-labels-idx1-ubyte.gz to ./mnist_data/MNIST/raw\n",
            "\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "[2022-02-16 04:00:40.868] Only use the front 300 images as TEST set.\n",
            "/usr/local/lib/python3.7/dist-packages/torch/utils/data/dataloader.py:481: UserWarning: This DataLoader will create 8 worker processes in total. Our suggested max number of worker in current system is 2, which is smaller than what this DataLoader is going to create. Please be aware that excessive worker creation might get DataLoader running slow or even freeze, lower the worker number to avoid potential slowness/freeze if necessary.\n",
            "  cpuset_checked))\n"
          ]
        }
      ],
      "source": [
        "random.seed(42)\n",
        "np.random.seed(42)\n",
        "torch.manual_seed(42)\n",
        "dataset = MNIST(\n",
        "    root='./mnist_data',\n",
        "    train_valid_split_ratio=[0.9, 0.1],\n",
        "    n_test_samples=300,\n",
        "    n_train_samples=500,\n",
        ")\n",
        "dataflow = dict()\n",
        "\n",
        "for split in dataset:\n",
        "    sampler = torch.utils.data.RandomSampler(dataset[split])\n",
        "    dataflow[split] = torch.utils.data.DataLoader(\n",
        "        dataset[split],\n",
        "        batch_size=10,\n",
        "        sampler=sampler,\n",
        "        num_workers=8,\n",
        "        pin_memory=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LpxOsZrRLUal"
      },
      "source": [
        "Then we set use_cuda, it depends on whether cuda is available.\n",
        "\n",
        "Create a device.\n",
        "\n",
        "Initialize the model, `n_epochs` to 15, Adam optimizer and cosine annealing learning rate scheduler.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "cmzcsyaCLZf_"
      },
      "outputs": [],
      "source": [
        "use_cuda = torch.cuda.is_available()\n",
        "device = torch.device(\"cuda\" if use_cuda else \"cpu\")\n",
        "model = HybridModel().to(device)\n",
        "model_without_qf = HybridModel_without_qf().to(device)\n",
        "n_epochs = 15\n",
        "optimizer = optim.Adam(model.parameters(), lr=5e-3, weight_decay=1e-4)\n",
        "scheduler = CosineAnnealingLR(optimizer, T_max=n_epochs)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ckdg6zccLwF3"
      },
      "source": [
        "### Train the model.\n",
        "\n",
        "When training the model, we iterate the dataloader. Get the\t`inputs` and `targets` data. Feed `inputs` to the model and get `outputs`. Calculate the negative loss likelihood loss(`F.nll_loss`). Reset all the gradients of parameters in the model to zero. Call `loss.backward()` to perform backpropagation. Call `optimizer.step()` to update all the parameters.\n",
        "\n",
        "After each epoch, we will valid the model. In validation, we can use qiskit remote because we don’t need to calculate gradients.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "xS7zGXVDLwuY",
        "outputId": "f7d7feb2-f4f7-447a-fb21-b39d2791cfa6"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Epoch 1:\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "/usr/local/lib/python3.7/dist-packages/torch/utils/data/dataloader.py:481: UserWarning: This DataLoader will create 8 worker processes in total. Our suggested max number of worker in current system is 2, which is smaller than what this DataLoader is going to create. Please be aware that excessive worker creation might get DataLoader running slow or even freeze, lower the worker number to avoid potential slowness/freeze if necessary.\n",
            "  cpuset_checked))\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "0.005\n",
            "test set accuracy: 0.8066666666666666\n",
            "test set loss: 0.6323180794715881\n",
            "Epoch 2:\n",
            "0.004945369001834514\n",
            "test set accuracy: 0.7766666666666666\n",
            "test set loss: 0.5900668501853943\n",
            "Epoch 3:\n",
            "0.004783863644106502\n",
            "test set accuracy: 0.8466666666666667\n",
            "test set loss: 0.48249581456184387\n",
            "Epoch 4:\n",
            "0.0045225424859373685\n",
            "test set accuracy: 0.8133333333333334\n",
            "test set loss: 0.5225163698196411\n",
            "Epoch 5:\n",
            "0.0041728265158971455\n",
            "test set accuracy: 0.8033333333333333\n",
            "test set loss: 0.6009621620178223\n",
            "Epoch 6:\n",
            "0.00375\n",
            "test set accuracy: 0.8333333333333334\n",
            "test set loss: 0.44394049048423767\n",
            "Epoch 7:\n",
            "0.0032725424859373687\n",
            "test set accuracy: 0.84\n",
            "test set loss: 0.4330306053161621\n",
            "Epoch 8:\n",
            "0.002761321158169134\n",
            "test set accuracy: 0.8366666666666667\n",
            "test set loss: 0.45171523094177246\n",
            "Epoch 9:\n",
            "0.002238678841830867\n",
            "test set accuracy: 0.8633333333333333\n",
            "test set loss: 0.4244077205657959\n",
            "Epoch 10:\n",
            "0.001727457514062632\n",
            "test set accuracy: 0.8633333333333333\n",
            "test set loss: 0.40085339546203613\n",
            "Epoch 11:\n",
            "0.0012500000000000007\n",
            "test set accuracy: 0.8533333333333334\n",
            "test set loss: 0.40397733449935913\n",
            "Epoch 12:\n",
            "0.0008271734841028553\n",
            "test set accuracy: 0.87\n",
            "test set loss: 0.3975270986557007\n",
            "Epoch 13:\n",
            "0.00047745751406263163\n",
            "test set accuracy: 0.8566666666666667\n",
            "test set loss: 0.4006715416908264\n",
            "Epoch 14:\n",
            "0.00021613635589349755\n",
            "test set accuracy: 0.8666666666666667\n",
            "test set loss: 0.39790403842926025\n",
            "Epoch 15:\n",
            "5.463099816548578e-05\n",
            "test set accuracy: 0.8666666666666667\n",
            "test set loss: 0.3979119062423706\n"
          ]
        }
      ],
      "source": [
        "accu_list1 = []\n",
        "loss_list1 = []\n",
        "accu_list2 = []\n",
        "loss_list2 = []\n",
        "\n",
        "def train(dataflow, model, device, optimizer):\n",
        "    for feed_dict in dataflow['train']:\n",
        "        inputs = feed_dict['image'].to(device)\n",
        "        targets = feed_dict['digit'].to(device)\n",
        "\n",
        "        outputs = model(inputs)\n",
        "        loss = F.nll_loss(outputs, targets)\n",
        "        optimizer.zero_grad()\n",
        "        loss.backward()\n",
        "        optimizer.step()\n",
        "        print(f\"loss: {loss.item()}\", end='\\r')\n",
        "\n",
        "\n",
        "def valid_test(dataflow, split, model, device, qiskit=False):\n",
        "    target_all = []\n",
        "    output_all = []\n",
        "    with torch.no_grad():\n",
        "        for feed_dict in dataflow[split]:\n",
        "            inputs = feed_dict['image'].to(device)\n",
        "            targets = feed_dict['digit'].to(device)\n",
        "\n",
        "            outputs = model(inputs, use_qiskit=qiskit)\n",
        "\n",
        "            target_all.append(targets)\n",
        "            output_all.append(outputs)\n",
        "        target_all = torch.cat(target_all, dim=0)\n",
        "        output_all = torch.cat(output_all, dim=0)\n",
        "\n",
        "    _, indices = output_all.topk(1, dim=1)\n",
        "    masks = indices.eq(target_all.view(-1, 1).expand_as(indices))\n",
        "    size = target_all.shape[0]\n",
        "    corrects = masks.sum().item()\n",
        "    accuracy = corrects / size\n",
        "    loss = F.nll_loss(output_all, target_all).item()\n",
        "\n",
        "    print(f\"{split} set accuracy: {accuracy}\")\n",
        "    print(f\"{split} set loss: {loss}\")\n",
        "\n",
        "    return accuracy, loss\n",
        "\n",
        "for epoch in range(1, n_epochs + 1):\n",
        "    # train\n",
        "    print(f\"Epoch {epoch}:\")\n",
        "    train(dataflow, model, device, optimizer)\n",
        "    print(optimizer.param_groups[0]['lr'])\n",
        "\n",
        "    # valid\n",
        "    accu, loss = valid_test(dataflow, 'test', model, device, )\n",
        "    accu_list1.append(accu)\n",
        "    loss_list1.append(loss)\n",
        "    scheduler.step()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dJkRbcfNEFzh"
      },
      "source": [
        "Train the model without quanvolutional filters."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "maFOnvDd1PrX",
        "outputId": "c039a787-a3bf-4ee5-8c1f-512c09773a81"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Epoch 1:\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "/usr/local/lib/python3.7/dist-packages/torch/utils/data/dataloader.py:481: UserWarning: This DataLoader will create 8 worker processes in total. Our suggested max number of worker in current system is 2, which is smaller than what this DataLoader is going to create. Please be aware that excessive worker creation might get DataLoader running slow or even freeze, lower the worker number to avoid potential slowness/freeze if necessary.\n",
            "  cpuset_checked))\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "0.005\n",
            "test set accuracy: 0.7733333333333333\n",
            "test set loss: 0.6043258905410767\n",
            "Epoch 2:\n",
            "0.004945369001834514\n",
            "test set accuracy: 0.8166666666666667\n",
            "test set loss: 0.5571645498275757\n",
            "Epoch 3:\n",
            "0.004783863644106502\n",
            "test set accuracy: 0.8466666666666667\n",
            "test set loss: 0.46128183603286743\n",
            "Epoch 4:\n",
            "0.0045225424859373685\n",
            "test set accuracy: 0.8366666666666667\n",
            "test set loss: 0.5158915519714355\n",
            "Epoch 5:\n",
            "0.0041728265158971455\n",
            "test set accuracy: 0.8666666666666667\n",
            "test set loss: 0.45338067412376404\n",
            "Epoch 6:\n",
            "0.00375\n",
            "test set accuracy: 0.8466666666666667\n",
            "test set loss: 0.4563254714012146\n",
            "Epoch 7:\n",
            "0.0032725424859373687\n",
            "test set accuracy: 0.8566666666666667\n",
            "test set loss: 0.4633018374443054\n",
            "Epoch 8:\n",
            "0.002761321158169134\n",
            "test set accuracy: 0.86\n",
            "test set loss: 0.46147480607032776\n",
            "Epoch 9:\n",
            "0.002238678841830867\n",
            "test set accuracy: 0.85\n",
            "test set loss: 0.45319321751594543\n",
            "Epoch 10:\n",
            "0.001727457514062632\n",
            "test set accuracy: 0.84\n",
            "test set loss: 0.46221110224723816\n",
            "Epoch 11:\n",
            "0.0012500000000000007\n",
            "test set accuracy: 0.8533333333333334\n",
            "test set loss: 0.4611275792121887\n",
            "Epoch 12:\n",
            "0.0008271734841028553\n",
            "test set accuracy: 0.8533333333333334\n",
            "test set loss: 0.4614029824733734\n",
            "Epoch 13:\n",
            "0.00047745751406263163\n",
            "test set accuracy: 0.8533333333333334\n",
            "test set loss: 0.4610340893268585\n",
            "Epoch 14:\n",
            "0.00021613635589349755\n",
            "test set accuracy: 0.8533333333333334\n",
            "test set loss: 0.46056315302848816\n",
            "Epoch 15:\n",
            "5.463099816548578e-05\n",
            "test set accuracy: 0.8533333333333334\n",
            "test set loss: 0.4606676697731018\n"
          ]
        }
      ],
      "source": [
        "optimizer = optim.Adam(model_without_qf.parameters(), lr=5e-3, weight_decay=1e-4)\n",
        "scheduler = CosineAnnealingLR(optimizer, T_max=n_epochs)\n",
        "for epoch in range(1, n_epochs + 1):\n",
        "    # train\n",
        "    print(f\"Epoch {epoch}:\")\n",
        "    train(dataflow, model_without_qf, device, optimizer)\n",
        "    print(optimizer.param_groups[0]['lr'])\n",
        "\n",
        "    # valid\n",
        "    accu, loss = valid_test(dataflow, 'test', model_without_qf, device)\n",
        "    accu_list2.append(accu)\n",
        "    loss_list2.append(loss)\n",
        "\n",
        "    scheduler.step()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AGuWP25IEIS1"
      },
      "source": [
        "### Compare Quanvolutional Neural Network with classical model.\n",
        "\n",
        "After training, we can plot the accuracy and loss curve. We can see that model with quanvolutional filter can achieve slightly higher accuracy than model without quanvolution."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 297
        },
        "id": "E_asswJ82Z2E",
        "outputId": "85b188d3-616b-4d50-d2ce-667c4dd05ff5"
      },
      "outputs": [
        {
          "data": {
            "image/png": "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MykoKOA///M/mTlzZr3jzZ8/nyNHjjB16lTuueceoqOj650HgHXr1pGZmcns2bMJDg5mx44d5OTk8Oijj1JeXk5sbCwZGRkkJCQwceJE0tLS2L59O3feeSe//OUv2/ivRQjRUVq6xHcAY9bcaVrra7TWywDHxQmraxk/fjzbtm0DIDMzk/Lycmw2G9u2bWPChAn1yj7//PNcfvnlZGVl8cILLwDwzTff8Mc//pGcnByOHDnC5583Hix+3rx5LFu2jD179ngd1+9//3syMzPZu3cvn332GXv37nVvi42NZffu3dx///0sWbIEk8nEbbfdxrvvvgvAV199RXJyMvHx8SxYsIC7776bvXv3Mnv2bBYuXOjV8QMDA3nuueeYNWsWWVlZzJpV//nulurNz89n+/btvP/++zzxxBON6l65ciWJiYls3ryZRYsWNXn8mTNnkp6ezurVq8nKyiIgIIAFCxawbt06d8L/zW9+4y5fU1NDZmamJCch/ERL1zFux5imfbNS6kPgLYyRJLymlJoC/AljRt1XtdbPN9j+IlDbIgsBemqtoy7kGA211NLxldGjR7Nr1y5KS0sJCgpi1KhRZGZmsm3bNpYuXdrq/ldeeaX7MlVaWhq5ublcc8017u21965qk92cOXPYuLH1fipr167llVdewW63k5+fT05ODsOHDwfg9ttvd8f+zjvvADBr1iyee+455s2bx1tvveVOKDt27HCXmTNnDr/61a+8PTUtaqneH//4x5hMJoYMGUJhYWGHHO/gwYPs37+fSZMmAeBwOEhISHBvb5hAhRCdq9kEpbV+D3hPKRUK3IYx5FFPpdTLwLta649bqtjVHf0lYBKQB+xUSq3XWud4HGORR/kFwMj2fJnOYrFY6NevHxkZGYwdO5bhw4ezefNmDh8+zODBg1vdPygoyP3ZbDZjt9u9PnZAQABOp9O9XPu8zdGjR1myZAk7d+4kOjqauXPn1nsWp/aYnse7+uqrOXz4MEVFRbz33ns89dRTbYqjI5758TwnFzrrc3O01qSmprJjx44mt4eGhnbIcYQQHaPVXnxa6/Na679prW8FkoBvMHr2teZK4LDW+ojWugajBXZbC+XvBN70ol6/NH78eJYsWcKECRMYP348K1euZOTIkY3uJYWHh1NWVnZBdUdFRREVFcX27dsBWL16tXtbSkoKWVlZOJ1O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",
            "text/plain": [
              "<Figure size 432x288 with 2 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light"
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "%matplotlib inline\n",
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "import matplotlib\n",
        "\n",
        "fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True)\n",
        "\n",
        "ax1.plot(accu_list1, label=\"with quanvolution filter\")\n",
        "ax1.plot(accu_list2, label=\"without quanvolution filter\")\n",
        "ax1.set_ylabel(\"Accuracy\")\n",
        "ax1.set_ylim([0.6, 1])\n",
        "ax1.set_xlabel(\"Epoch\")\n",
        "ax1.legend()\n",
        "\n",
        "ax2.plot(loss_list1, label=\"with quanvolution filter\")\n",
        "ax2.plot(loss_list2, label=\"without quanvolution filter\")\n",
        "ax2.set_ylabel(\"Loss\")\n",
        "ax2.set_ylim([0, 2])\n",
        "ax2.set_xlabel(\"Epoch\")\n",
        "ax2.legend()\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PMU08GNiEKTW"
      },
      "source": [
        "Here we can also see the image before quanvolutional filter and after quanvolutional filter."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 690
        },
        "id": "710VuJZMJGGe",
        "outputId": "e02f51bf-08bb-4e71-9343-2ebe4bdef14c"
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "/usr/local/lib/python3.7/dist-packages/torch/utils/data/dataloader.py:481: UserWarning: This DataLoader will create 8 worker processes in total. Our suggested max number of worker in current system is 2, which is smaller than what this DataLoader is going to create. Please be aware that excessive worker creation might get DataLoader running slow or even freeze, lower the worker number to avoid potential slowness/freeze if necessary.\n",
            "  cpuset_checked))\n"
          ]
        },
        {
          "data": {
            "image/png": "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lFt7/24DsBtAcaTWHwBjok6zuDAm6qI0LoyJOu4//lhX/DEm6rj/+IuLmER7klwM4IjX66PQ6D9fCFEO4BwAm3rfuksI8aUQ4gUhRFYEi8KYqIuKuDAm6qIoLoyJuqiIC2OiLoriwpioi4q4MCb+hhqTaE+So4IQIg3A/wG4V0p5BsDTAEYAmAygAcATGhZPE4yJP8ZEHePijzHxx5ioY1z8MSb+GBN/oYhJtCfJ9QBKvV6X9L4XMUIII3qC/JqU8m0AkFKekFI6pZQuAM+h57JCpDAm6jSNC2OiLgrjwpio4/7jj3XFH2OijvuPv7iISbQnyZsBjBJCVAghTABuBPBepFYuhBAAlgHYLaX8rdf7RV6zzQOwM1JlAmMSiGZxYUzURWlcGBN13H/8sa74Y0zUcf/xFxcxMYS+eKEjpXQIIe4CsAo9d0q+IKX8KoJFuADA/wOwQwixvfe9/wSwQAgxGYAEUAfgjkgViDFRp3FcGBN1URcXxkQd9x9/rCv+GBN13H/8xUtM+MQ9IiIiIiKFaO9uQUREREQUcUySiYiIiIgUmCQTERERESkwSSYiIiIiUmCSTERERESkwCSZiIiIiEiBSTIRERERkQKTZCIiIiIiBSbJREREREQKTJKJiIiIiBSYJBMRERERKTBJJiIiIiJSYJJMRERERKTAJJmIiIiISIFJMhERERGRApNkIiIiIiIFJslERERERApMkomIiIiIFJgkExEREREpMEkmIiIiIlJgkkxEREREpMAkmYiIiIhIgUkyEREREZECk2QiIiIiIgUmyURERERECkySiYiIiIgUmCQTERERESkwSSYiIiIiUmCSTERERESkwCSZiIiIiEiBSTIRERERkQKTZCIiIiIiBSbJREREREQKTJKJiIiIiBSYJBMRERERKTBJJiIiIiJSYJJMRERERKTAJJmIiIiISIFJMhERERGRApNkIiIiIiIFJslERERERApMkomIiIiIFJgkExEREREpMEkmIiIiIlJgkkxEREREpMAkmYiIiIhIgUkyEREREZECk2QiIiIiIgUmyURERERECkySiYiIiIgUmCQTERERESkwSSYiIiIiUmCSTERERESkwCSZiIiIiEiBSTIRERERkQKTZCIiIiIiBSbJREREREQKTJKJiIiIiBSYJBMRERERKTBJJiIiIiJSYJJMRERERKTA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DBZj4k+rmACMixrGxB9j4i+aYwIwLmoYE3+MibqYj0ssJMmbAYwSQlQIIUwAbgTwXgTW+x6ARb1/LwLwbgTWGSzGxJ9WMQEYFzWMiT/GxF80xwRgXNQwJv4YE3WxHxcpZdRPAK4CsA9ALYCfhmH5bwBoAGBHT5+ZWwDkoOeuyK8BrAaQrXUcGBNtY8K4MCaMSWLFhHFhTBiTxI4LHyZCRERERKQQC90tiIiIiIgiikkyEREREZECk2QiIiIiIgUmyURERERECkySiYiIiIgUmCQTERERESkwSSYiIiIiUmCSTERERESkwCSZiIiIiEiBSTIRERERkQKTZCIiIiIiBSbJREREREQKTJKJiIiIiBSYJBMRERERKTBJJiIiIiJSYJJMRERERKTAJJmIiIiISIFJMhERERGRApNkIiIiIiIFJslERERERApMkomIiIiIFJgkExER0T9G8QAAIABJREFUEREpMEkmIiIiIlJgkkxEREREpMAkmYiIiIhIgUkyEREREZECk2QiIiIiIgUmyURERERECkySiYiIiIgUmCQTERERESkwSSYiIiIiUmCSTERERESkwCSZiIiIiEiBSTIRERERkQKTZCIiIiIiBSbJREREREQKTJKJiIiIiBSYJBMRERERKTBJJiIiIiJSYJJMRERERKTAJJmIiIiISIFJMhERERGRApNkIiIiIiIFJslERERERApMkomIiIiIFJgkExEREREpMEkmIiIiIlJgkkxEREREpMAkmYiIiIhIgUkyEREREZECk2QiIiIiIgUmyURERERECkySiYiIiIgUmCQTERERESkwSSYiIiIiUmCSTERERESkwCSZiIiIiEiBSTIRERERkQKTZCIiIiIiBSbJREREREQKTJKJiIiIiBSYJBMRERERKTBJJiIiIiJSYJJMRERERKTAJJmIiIiISIFJMhERERGRApNkIiIiIiIFJslERERERApMkomIiIiIFJgkExEREREpMEkmIiIiIlJgkkxEREREpMAkmYiIiIhIgUkyEREREZECk2QiIiIiIgUmyURERERECkySiYiIiIgUBpUkCyFmhbogRERERETRQkgpB/4lIQ5LKcvCUB4iIiIiIs0ZAn0ghHgv0EcAcoayUiHElQB+D0AP4Hkp5a+HsjwiIiIiolAK2JIshGgGsBBAu/IjAP8rpSwY1AqF0APY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",
            "text/plain": [
              "<Figure size 720x720 with 50 Axes>"
            ]
          },
          "metadata": {
            "needs_background": "light"
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import matplotlib\n",
        "\n",
        "n_samples = 10\n",
        "n_channels = 4\n",
        "for feed_dict in dataflow['test']:\n",
        "  inputs = feed_dict['image'].to(device)\n",
        "  break \n",
        "sample = inputs[:n_samples]\n",
        "after_quanv = model.qf(sample).view(n_samples, 14*14, 4).cpu().detach().numpy()\n",
        "\n",
        "fig, axes = plt.subplots(1 + n_channels, n_samples, figsize=(10, 10))\n",
        "for k in range(n_samples):\n",
        "    axes[0, 0].set_ylabel(\"image\")\n",
        "    if k != 0:\n",
        "        axes[0, k].yaxis.set_visible(False)\n",
        "    \n",
        "    norm = matplotlib.colors.Normalize(vmin=0, vmax=1)\n",
        "    \n",
        "    axes[0, k].imshow(sample[k, 0, :, :].cpu(), norm=norm, cmap=\"gray\")\n",
        "\n",
        "    for c in range(n_channels):\n",
        "        axes[c + 1, 0].set_ylabel(\"channel {}\".format(c))\n",
        "        if k != 0:\n",
        "            axes[c, k].yaxis.set_visible(False)\n",
        "        axes[c + 1, k].imshow(after_quanv[k, :, c].reshape(14, 14), norm=norm, cmap=\"gray\")\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6Z_yKJ7WNKCQ"
      },
      "source": [
        "### Evaluate on real quantum computer.\n",
        "\n",
        "At last, we can run our quanvolutional filter on IBMQ’s real quantum machine. The process is really slow so I will not show it here. If you have higher priority access to IBMQ qiskit, you can check the code cell in installation and replace our token with your advance token. That will make the process faster."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "mR6wlvcbMLwx"
      },
      "outputs": [],
      "source": [
        "# test\n",
        "valid_test(dataflow, 'test', model, device, qiskit=False)\n",
        "\n",
        "# run on Qiskit simulator and real Quantum Computers\n",
        "try:\n",
        "    from qiskit import IBMQ\n",
        "    from torchquantum.plugin import QiskitProcessor\n",
        "    # firstly perform simulate\n",
        "    print(f\"\\nTest with Qiskit Simulator\")\n",
        "    processor_simulation = QiskitProcessor(use_real_qc=False)\n",
        "    model.qf.set_qiskit_processor(processor_simulation)\n",
        "    valid_test(dataflow, 'test', model, device, qiskit=True)\n",
        "    # then try to run on REAL QC\n",
        "    backend_name = 'ibmq_quito'\n",
        "    print(f\"\\nTest on Real Quantum Computer {backend_name}\")\n",
        "    processor_real_qc = QiskitProcessor(use_real_qc=True,backend_name=backend_name)\n",
        "    model.qf.set_qiskit_processor(processor_real_qc)\n",
        "    valid_test(dataflow, 'test', model, device, qiskit=True)\n",
        "except ImportError:\n",
        "    print(\"Please install qiskit, create an IBM Q Experience Account and \"\n",
        "          \"save the account token according to the instruction at \"\n",
        "          \"'https://github.com/Qiskit/qiskit-ibmq-provider', \"\n",
        "          \"then try again.\")\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NkbKoXwfnwAC"
      },
      "source": [
        "## Trainable Quanvolutional Filter\n",
        "In this section, we consider the case that quanvolutional filters are trainable, and we compare various models with nearly the same number of trainale parameters. The four model compared here are described by the following figure.\n",
        "\n",
        "\n",
        "<div align=\"center\">\n",
        "<img src=\"https://github.com/mit-han-lab/torchquantum/blob/master/figs/4models.png?raw=true\" alt=\"conv-full-layer\" width=\"600\">\n",
        "</div>\n",
        "\n",
        "The Model1 contains a trainable quanvolutional filter and a fully connected layer.\n",
        "\n",
        "The Model2 contains a trainable quanvolutional filter and a quantum fully connected layer. We use `U3CU3Layer0` from `torchquantum.layers` to implement the QFC layer.\n",
        "\n",
        "When building the ansatz part of the QFC, we need to pass a dict describing the architecture of the ansatz. Here the dict is `{'n_wires': self.n_wires, 'n_blocks': 4, 'n_layers_per_block': 2}`, which means the ansatz contains n_wires qubits, there are 4 blocks and in each block are 2 layers. Passing the arch to `U3CU3Layer0` we will get a trainable ansatz with 4 blocks and in each block contains 4 U3 gates followed by 4 CU3 gates.\n",
        "\n",
        "The Model3 is simply a QFC layer.\n",
        "\n",
        "The Model4 is two fully connected layers.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "b46xdprmqcgK"
      },
      "outputs": [],
      "source": [
        "from torchquantum.encoding import encoder_op_list_name_dict\n",
        "from torchquantum.layers import U3CU3Layer0\n",
        "\n",
        "class TrainableQuanvFilter(tq.QuantumModule):\n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.n_wires = 4\n",
        "        self.q_device = tq.QuantumDevice(n_wires=self.n_wires)\n",
        "        self.encoder = tq.GeneralEncoder(\n",
        "        [   {'input_idx': [0], 'func': 'ry', 'wires': [0]},\n",
        "            {'input_idx': [1], 'func': 'ry', 'wires': [1]},\n",
        "            {'input_idx': [2], 'func': 'ry', 'wires': [2]},\n",
        "            {'input_idx': [3], 'func': 'ry', 'wires': [3]},])\n",
        "        \n",
        "        self.arch = {'n_wires': self.n_wires, 'n_blocks': 5, 'n_layers_per_block': 2}\n",
        "        self.q_layer = U3CU3Layer0(self.arch)\n",
        "        self.measure = tq.MeasureAll(tq.PauliZ)\n",
        "\n",
        "    def forward(self, x, use_qiskit=False):\n",
        "        bsz = x.shape[0]\n",
        "        x = F.avg_pool2d(x, 6).view(bsz, 4, 4)\n",
        "        size = 4\n",
        "        stride = 2\n",
        "        x = x.view(bsz, size, size)\n",
        "\n",
        "        data_list = []\n",
        "\n",
        "        for c in range(0, size, stride):\n",
        "            for r in range(0, size, stride):\n",
        "                data = torch.transpose(torch.cat((x[:, c, r], x[:, c, r+1], x[:, c+1, r], x[:, c+1, r+1])).view(4, bsz), 0, 1)\n",
        "                if use_qiskit:\n",
        "                    data = self.qiskit_processor.process_parameterized(\n",
        "                        self.q_device, self.encoder, self.q_layer, self.measure, data)\n",
        "                else:\n",
        "                    self.encoder(self.q_device, data)\n",
        "                    self.q_layer(self.q_device)\n",
        "                    data = self.measure(self.q_device)\n",
        "\n",
        "                data_list.append(data.view(bsz, 4))\n",
        "        \n",
        "        # transpose to (bsz, channel, 2x2)\n",
        "        result = torch.transpose(torch.cat(data_list, dim=1).view(bsz, 4, 4), 1, 2).float()\n",
        "        \n",
        "        return result\n",
        "\n",
        "class QuantumClassifier(torch.nn.Module):\n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.n_wires = 4\n",
        "        self.q_device = tq.QuantumDevice(n_wires=4)\n",
        "        self.encoder = tq.GeneralEncoder(encoder_op_list_name_dict['4x4_ryzxy'])\n",
        "        self.arch = {'n_wires': self.n_wires, 'n_blocks': 8, 'n_layers_per_block': 2}\n",
        "        self.ansatz = U3CU3Layer0(self.arch)\n",
        "        self.measure = tq.MeasureAll(tq.PauliZ)\n",
        "    \n",
        "    def forward(self, x, use_qiskit=False):\n",
        "        bsz = x.shape[0]\n",
        "        x = F.avg_pool2d(x, 6).view(bsz, 16)\n",
        "\n",
        "        if use_qiskit:\n",
        "            x = self.qiskit_processor.process_parameterized(\n",
        "                self.q_device, self.encoder, self.q_layer, self.measure, x)\n",
        "        else:\n",
        "            self.encoder(self.q_device, x)\n",
        "            self.ansatz(self.q_device)\n",
        "            x = self.measure(self.q_device)\n",
        "\n",
        "        return x\n",
        "\n",
        "class QFC(tq.QuantumModule):\n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.n_wires = 4\n",
        "        self.q_device = tq.QuantumDevice(n_wires=self.n_wires)\n",
        "        self.encoder = tq.GeneralEncoder(encoder_op_list_name_dict['4x4_ryzxy'])\n",
        "        self.arch = {'n_wires': self.n_wires, 'n_blocks': 4, 'n_layers_per_block': 2}\n",
        "\n",
        "        self.q_layer = U3CU3Layer0(self.arch)\n",
        "        self.measure = tq.MeasureAll(tq.PauliZ)\n",
        "\n",
        "    def forward(self, x, use_qiskit=False):\n",
        "        bsz = x.shape[0]\n",
        "        data = x\n",
        "        if use_qiskit:\n",
        "            data = self.qiskit_processor.process_parameterized(\n",
        "                self.q_device, self.encoder, self.q_layer, self.measure, data)\n",
        "        else:\n",
        "            self.encoder(self.q_device, data)\n",
        "            self.q_layer(self.q_device)\n",
        "            data = self.measure(self.q_device)\n",
        "        return data\n",
        "\n",
        "\n",
        "class Model1(torch.nn.Module):\n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.qf = TrainableQuanvFilter()\n",
        "        self.linear = torch.nn.Linear(16, 4)\n",
        "    \n",
        "    def forward(self, x, use_qiskit=False):\n",
        "        x = x.view(-1, 28, 28)\n",
        "        x = self.qf(x)\n",
        "        x = x.reshape(-1, 16)\n",
        "        x = self.linear(x)\n",
        "        return F.log_softmax(x, -1)\n",
        "\n",
        "class Model2(torch.nn.Module):\n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.qf = TrainableQuanvFilter()\n",
        "        self.qfc = QFC()\n",
        "    \n",
        "    def forward(self, x, use_qiskit=False):\n",
        "        x = x.view(-1, 28, 28)\n",
        "        x = self.qf(x)\n",
        "        x = x.reshape(-1, 16)\n",
        "        x = self.qfc(x)\n",
        "        return F.log_softmax(x, -1)\n",
        "\n",
        "class Model3(torch.nn.Module):\n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.qfc = QuantumClassifier()\n",
        "    \n",
        "    def forward(self, x, use_qiskit=False):\n",
        "        x = self.qfc(x)\n",
        "        return F.log_softmax(x, -1)\n",
        "\n",
        "class Model4(torch.nn.Module):\n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.linear1 = torch.nn.Linear(16, 9)\n",
        "        self.linear2 = torch.nn.Linear(9, 4)\n",
        "    \n",
        "    def forward(self, x, use_qiskit=False):\n",
        "        x = x.view(-1, 28, 28)\n",
        "        bsz = x.shape[0]\n",
        "        x = F.avg_pool2d(x, 6).view(bsz, 16)\n",
        "\n",
        "        x = self.linear1(x)\n",
        "        x = self.linear2(x)\n",
        "        return F.log_softmax(x, -1)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PkTvypANsRIL"
      },
      "source": [
        "Here we do the MNIST 4 classification tasks."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "veZRy9L-sKBC"
      },
      "outputs": [],
      "source": [
        "dataset = MNIST(\n",
        "    root='./mnist_data',\n",
        "    train_valid_split_ratio=[0.9, 0.1],\n",
        "    digits_of_interest=[0, 1, 2, 3],\n",
        "    n_test_samples=300,\n",
        "    n_train_samples=500,\n",
        ")\n",
        "\n",
        "dataflow = dict()\n",
        "for split in dataset:\n",
        "    sampler = torch.utils.data.RandomSampler(dataset[split])\n",
        "    dataflow[split] = torch.utils.data.DataLoader(\n",
        "        dataset[split],\n",
        "        batch_size=10,\n",
        "        sampler=sampler,\n",
        "        num_workers=8,\n",
        "        pin_memory=True)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kDvJ7RmcsqAy"
      },
      "outputs": [],
      "source": [
        "use_cuda = torch.cuda.is_available()\n",
        "device = torch.device(\"cuda\" if use_cuda else \"cpu\")\n",
        "accus = []\n",
        "\n",
        "model_list = [Model1().to(device), Model2().to(device), Model3().to(device), Model4().to(device)]\n",
        "for model in model_list:\n",
        "  n_epochs = 15\n",
        "\n",
        "  optimizer = optim.Adam(model.parameters(), lr=5e-3, weight_decay=1e-4)\n",
        "  scheduler = CosineAnnealingLR(optimizer, T_max=n_epochs)\n",
        "  for epoch in range(1, n_epochs + 1):\n",
        "      # train\n",
        "      print(f\"Epoch {epoch}:\")\n",
        "      train(dataflow, model, device, optimizer)\n",
        "      print(optimizer.param_groups[0]['lr'])\n",
        "      # valid\n",
        "      accu, loss = valid_test(dataflow, 'test', model, device)\n",
        "      scheduler.step()\n",
        "  accus.append(accu)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "wXfgOqfr42sx"
      },
      "outputs": [],
      "source": [
        "for i, accu in enumerate(accus):\n",
        "  print('accuracy of model{0}: {1}'.format(i+1, accu))"
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "collapsed_sections": [
        "pfwd2SNaOA4z"
      ],
      "name": "Quanvolution example",
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3.10.5 64-bit ('3.10.5')",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "version": "3.10.5"
    },
    "vscode": {
      "interpreter": {
        "hash": "0b2ecac4133ec89d164eeefcc4a6d2d5c9a232a58380a21c437a4c41906128d5"
      }
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "18acae4757154a10a7e2b9ebe4fbd53b": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "1c75908cdb0d4909a266ef3f0184c13d": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "237d834d5fd74efa947683722d3e0e37": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "FloatProgressModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "FloatProgressModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "ProgressView",
            "bar_style": "success",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_c893fabe4af6410d837a0bd191df61d9",
            "max": 1648877,
            "min": 0,
            "orientation": "horizontal",
            "style": "IPY_MODEL_f86c7ffecc394345a4eeb587cfd404d1",
            "value": 1648877
          }
        },
        "23dbd6346f684afebcc4ea0d3e72a67e": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HBoxModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HBoxModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HBoxView",
            "box_style": "",
            "children": [
              "IPY_MODEL_3b090dcf208c4822892a0afc2ba2e6a9",
              "IPY_MODEL_d0a2f52a311541a686f592a985e1aac0",
              "IPY_MODEL_41e329d1bd764c7cad4d2e834df50cd9"
            ],
            "layout": "IPY_MODEL_e85d5726a566462e962baa75f32074d6"
          }
        },
        "26d0390ad17048799741582271721a3e": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "29be09a9c5344928a9d2dda75ed8680c": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_45f166ea914e49c5bcf2ec39a649e351",
            "placeholder": "​",
            "style": "IPY_MODEL_f69883e80817409c9a10a2ec6d6ef68c",
            "value": " 1649664/? [00:00&lt;00:00, 6011445.81it/s]"
          }
        },
        "30b8e4960e564891ad81ac242c228b25": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_a8e8fb1c355445698cbc828dddffb9e5",
            "placeholder": "​",
            "style": "IPY_MODEL_d274e40c0adb4d3e80e8d1cf5ad475ee",
            "value": ""
          }
        },
        "32bd67ddf3a44b879cb123aa797627c0": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_e81b4f6589d649758fd2cd18da8ab35f",
            "placeholder": "​",
            "style": "IPY_MODEL_7584295a605c4a99a4dccce31be4cb2d",
            "value": ""
          }
        },
        "34e1a2b9f934411090026a0ee98a3b5b": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "364f865b5e334ac6add27ef1a32b8173": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "393cc69622f3428fba3e10886e5ab65d": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "3b090dcf208c4822892a0afc2ba2e6a9": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_b6d2f65a2e644523b7ecc6e3e9e17de3",
            "placeholder": "​",
            "style": "IPY_MODEL_5de520efee524ca28ed5b1b42861bef7",
            "value": ""
          }
        },
        "3f37e8639ddd4a6eac44420ce3275cd7": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "41e329d1bd764c7cad4d2e834df50cd9": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_26d0390ad17048799741582271721a3e",
            "placeholder": "​",
            "style": "IPY_MODEL_c168c7416db742f5bc74d45fe4a9bf05",
            "value": " 29696/? [00:00&lt;00:00, 1002987.94it/s]"
          }
        },
        "45f166ea914e49c5bcf2ec39a649e351": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "4abe9a5443514e00a536c839a9a5e04d": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "ProgressStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "ProgressStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "bar_color": null,
            "description_width": ""
          }
        },
        "5335eb0e67f84c85b9efacc7793d24fd": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "5953a85cd7334c828cf5005b2807fa41": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_364f865b5e334ac6add27ef1a32b8173",
            "placeholder": "​",
            "style": "IPY_MODEL_18acae4757154a10a7e2b9ebe4fbd53b",
            "value": ""
          }
        },
        "5de520efee524ca28ed5b1b42861bef7": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "694229176eb84488811763e57ccdbd9f": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "7584295a605c4a99a4dccce31be4cb2d": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "7cbce63b72c843e9ad824dce59a7e2fb": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_393cc69622f3428fba3e10886e5ab65d",
            "placeholder": "​",
            "style": "IPY_MODEL_1c75908cdb0d4909a266ef3f0184c13d",
            "value": " 5120/? [00:00&lt;00:00, 87902.47it/s]"
          }
        },
        "952170c8ff4d4fa9b7141d372b35cdd1": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "FloatProgressModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "FloatProgressModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "ProgressView",
            "bar_style": "success",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_3f37e8639ddd4a6eac44420ce3275cd7",
            "max": 4542,
            "min": 0,
            "orientation": "horizontal",
            "style": "IPY_MODEL_e2b60171e7ca45bea357831419d2f9c6",
            "value": 4542
          }
        },
        "a8e8fb1c355445698cbc828dddffb9e5": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "ace3e747ccfd4f9f9faf46ce34936ce1": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HTMLModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_34e1a2b9f934411090026a0ee98a3b5b",
            "placeholder": "​",
            "style": "IPY_MODEL_5335eb0e67f84c85b9efacc7793d24fd",
            "value": " 9913344/? [00:00&lt;00:00, 30809548.66it/s]"
          }
        },
        "ae65786c8b1e4e789ecb72bcd6b9b211": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HBoxModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HBoxModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HBoxView",
            "box_style": "",
            "children": [
              "IPY_MODEL_5953a85cd7334c828cf5005b2807fa41",
              "IPY_MODEL_952170c8ff4d4fa9b7141d372b35cdd1",
              "IPY_MODEL_7cbce63b72c843e9ad824dce59a7e2fb"
            ],
            "layout": "IPY_MODEL_cfc67a5bebd247838d29b9babacbc103"
          }
        },
        "b2ca643df597463dad1d5efe8abf64c4": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "b6d2f65a2e644523b7ecc6e3e9e17de3": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "c168c7416db742f5bc74d45fe4a9bf05": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "c46454929cae4e89976f42d9bc391a94": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "FloatProgressModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "FloatProgressModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "ProgressView",
            "bar_style": "success",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_dc961678433f488babca027e197d2aa1",
            "max": 9912422,
            "min": 0,
            "orientation": "horizontal",
            "style": "IPY_MODEL_d312e5166b28438da2b9e91de91f0e09",
            "value": 9912422
          }
        },
        "c893fabe4af6410d837a0bd191df61d9": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "c8c570bdf96340c1bbf4e612f3d0c3c4": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "cfc67a5bebd247838d29b9babacbc103": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "d0a2f52a311541a686f592a985e1aac0": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "FloatProgressModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "FloatProgressModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "ProgressView",
            "bar_style": "success",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_b2ca643df597463dad1d5efe8abf64c4",
            "max": 28881,
            "min": 0,
            "orientation": "horizontal",
            "style": "IPY_MODEL_4abe9a5443514e00a536c839a9a5e04d",
            "value": 28881
          }
        },
        "d274e40c0adb4d3e80e8d1cf5ad475ee": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "d312e5166b28438da2b9e91de91f0e09": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "ProgressStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "ProgressStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "bar_color": null,
            "description_width": ""
          }
        },
        "dc961678433f488babca027e197d2aa1": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "ddcca6cc591f45a887f80bcc5d27ce13": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HBoxModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HBoxModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HBoxView",
            "box_style": "",
            "children": [
              "IPY_MODEL_30b8e4960e564891ad81ac242c228b25",
              "IPY_MODEL_c46454929cae4e89976f42d9bc391a94",
              "IPY_MODEL_ace3e747ccfd4f9f9faf46ce34936ce1"
            ],
            "layout": "IPY_MODEL_c8c570bdf96340c1bbf4e612f3d0c3c4"
          }
        },
        "e2b60171e7ca45bea357831419d2f9c6": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "ProgressStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "ProgressStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "bar_color": null,
            "description_width": ""
          }
        },
        "e81b4f6589d649758fd2cd18da8ab35f": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "e85d5726a566462e962baa75f32074d6": {
          "model_module": "@jupyter-widgets/base",
          "model_module_version": "1.2.0",
          "model_name": "LayoutModel",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "f314f3212d8f49468ccce3ad1cb8af6e": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "HBoxModel",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HBoxModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HBoxView",
            "box_style": "",
            "children": [
              "IPY_MODEL_32bd67ddf3a44b879cb123aa797627c0",
              "IPY_MODEL_237d834d5fd74efa947683722d3e0e37",
              "IPY_MODEL_29be09a9c5344928a9d2dda75ed8680c"
            ],
            "layout": "IPY_MODEL_694229176eb84488811763e57ccdbd9f"
          }
        },
        "f69883e80817409c9a10a2ec6d6ef68c": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "DescriptionStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "f86c7ffecc394345a4eeb587cfd404d1": {
          "model_module": "@jupyter-widgets/controls",
          "model_module_version": "1.5.0",
          "model_name": "ProgressStyleModel",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "ProgressStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "bar_color": null,
            "description_width": ""
          }
        }
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
